package maquina;
import java.lang.Character;
import java.util.Hashtable;

import maquina.excepciones.CadenaNoAptaComoByteException;

public class Util {

	@SuppressWarnings("serial")
	private static final Hashtable<String,String> exponentes=new Hashtable<String,String>() {{
		put("0","000");
		put("1","001");
		put("2","010");
		put("3","011");
		put("4","100");
		put("5","101");
		put("6","110");
		put("7","111");		
		}};	
		
		@SuppressWarnings("serial")
		private static final Hashtable<String,String> exponentes2=new Hashtable<String,String>() {{
			put("000","0");
			put("001","1");
			put("010","2");
			put("011","3");
			put("100","4");
			put("101","5");
			put("110","6");
			put("111","7");		
			}};
	
	public String decimalABinarioFlotante(double numero){
		
		if (numero>=-0.0625 && numero<0.06640625){
			return "00000000";
		} else if (Math.abs(numero)>=16){
			return "";
		}
		String resultado = "";
		
		if (numero>=0){
			resultado="0";
		} else {
			resultado="1";
			numero=-numero;
		}
		
		String mantisa = "";
		String exponente = "";
		int expo = 0;

		int parteEntera= (int)numero;
		double parteDecimal = numero - parteEntera;
	
		while(parteEntera > 1){ 
			mantisa=Character.forDigit(parteEntera%2,10)+mantisa; 
			parteEntera /= 2; 
		}

		mantisa=Character.forDigit(parteEntera,10)+mantisa;

		while (mantisa.startsWith("0")){
			mantisa=mantisa.substring(1);
		}
		if (parteEntera!=0){
			mantisa=mantisa.substring(1); // Descarto el primer 1.
		}
		
		expo=mantisa.length();
		if (expo>3){
			return ""; // Hay desborde.
		}
		
		boolean primerUnoEncontrado = false;
		while(parteDecimal > 0 && mantisa.length()<4){ 
			parteDecimal = parteDecimal*2;
			int j = (int)parteDecimal;
			mantisa+=Character.forDigit(j,10);
			if (parteEntera==0 && ! primerUnoEncontrado){
				expo--;
				if (Character.forDigit(j,10)=='1'){
					primerUnoEncontrado=true;
					mantisa="";
				}
			}
			parteDecimal = parteDecimal - (int)parteDecimal;			
		}
		while (mantisa.length()<4){
			mantisa+="0";
		}
		
		exponente = Util.exponentes.get(String.valueOf(expo+4)); // Exceso 4.
		
		resultado=resultado+exponente+mantisa;
		return resultado;
	}
	
	public double binarioFlotanteADecimal(String binario){
		
		if (binario.equals("00000000")){
			return 0;
		}
		
		double resultado = 0;
		
		String exponente=binario.substring(1, 4);
		String mantisa="1"+binario.substring(4, 8);
		String signo =binario.charAt(0)+"";
		int expo = Character.getNumericValue(Util.exponentes2.get(exponente).charAt(0)) -4;
		
		for (int i=0;i<5;i++){
			resultado+=Character.getNumericValue(mantisa.charAt(i)) * (Math.pow(2,expo));
			expo--;
		}		
		if (signo.equals("1")){
			resultado=-resultado;
		}

		return resultado;
	}	
	
	public String enteroABinario(int numero) throws  CadenaNoAptaComoByteException{
		
		String resultado="";		
		if (numero<-128 || numero>127){
			return resultado;
		}
		
		boolean negativo = false;
		if (numero<0){
			negativo=true;
			numero=-numero;
		}
		
		for (int i=7;i>=0;i--){
			if (numero>=Math.pow(2, i)){
				resultado+="1";
				numero-=Math.pow(2, i);
			} else {
				resultado+="0";
			}
		}
		if (negativo){
			String aux = "";
			for (int i=0;i<8;i++){
				if (resultado.charAt(i)=='0'){
					aux+="1";
				} else {
					aux+="0";
				}
			}
			Alu alu = new Alu();
			resultado = alu.suma2(new ByteString(aux), new ByteString("00000001")).aStringBinario();
		}

		return resultado;
	}
	
	public int binarioAEntero(String binario) throws  CadenaNoAptaComoByteException{
		int resultado = 0;
		boolean negativo = false;
		
		if (binario.charAt(0)=='1'){
			// Es negativo.
			negativo=true;
			
			Alu alu = new Alu();
			String aux = alu.suma2(new ByteString(binario), new ByteString("11111111")).aStringBinario();
			binario="";
			for (int i=0;i<8;i++){
				if (aux.charAt(i)=='0'){
					binario+="1";
				} else {
					binario+="0";
				}
			}			
		}
		for (int i=7;i>=0;i--){
			if (binario.charAt(7-i)=='1'){
				resultado+=Math.pow(2, i);
			}
		}
		if(negativo){
			resultado=-resultado;
		}
		return resultado;
	}	
}